package com.xique.park.service.service.impl;

import com.xique.common.core.constant.UserConstants;
import com.xique.common.core.domain.R;
import com.xique.common.core.enums.AreaLevel;
import com.xique.common.core.utils.DateUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.security.service.TokenService;
import com.xique.park.bean.domain.Area;
import com.xique.park.bean.domain.ParkInfo;
import com.xique.park.bean.dto.*;
import com.xique.park.bean.vo.screen.*;
import com.xique.park.bean.vo.web.parkinfo.ParkBaseInfoVo;
import com.xique.park.service.service.*;
import com.xique.system.api.RemoteSystemDeptService;
import com.xique.system.api.RemoteSystemProjectService;
import com.xique.system.api.dto.SystemDeptDTO;
import com.xique.system.api.dto.SystemProjectDTO;
import com.xique.system.api.model.LoginSystemUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 地图数据大屏服务实现
 *
 * @author wld
 * @date 2022/3/9 10:05
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ScreenServiceImpl implements IScreenService {

    private final IParkInService parkInService;

    private final IParkOutService parkOutService;

    private final IPayOrderService payOrderService;

    private final IParkInfoService parkInfoService;

    private final IParkDeviceNewService parkDeviceNewService;

    private final IParkLaneService parkLaneService;

    private final IAreaService areaService;

    private final TokenService tokenService;

    private final RemoteSystemDeptService remoteSystemDeptService;

    private final RemoteSystemProjectService remoteSystemProjectService;

    private static final String LOGIN_USER_GET_ERROR = "登录用户获取失败";

    @Override
    public ScreenVo info(Integer country, Integer province, Integer city, Integer district, Long parkInfoId) {
        if (parkInfoId != null) {
            // 按项目去统计
            return statisticalItems(province, city, district, parkInfoId);
        } else if (district != null) {
            // 按区县去统计
            return statisticalDistrict(province, city, district);
        } else if (city != null) {
            // 按市去统计
            return statisticalCity(province, city);
        } else if (province != null) {
            // 按省去统计
            return statisticalProvince(province);
        } else if (country != null) {
            // 统计全国
            return nationalStatistics();
        } else {
            // 统计全国
            return nationalStatistics();
        }
    }

    /**
     * 按项目去统计
     */
    private ScreenVo statisticalItems(Integer province, Integer city, Integer district, Long parkInfoId) {
        return statistics(province, city, district, parkInfoId);
    }

    /**
     * 按区县去统计
     */
    private ScreenVo statisticalDistrict(Integer province, Integer city, Integer district) {
        return statistics(province, city, district, null);
    }

    /**
     * 按市去统计
     */
    private ScreenVo statisticalCity(Integer province, Integer city) {
        return statistics(province, city, null, null);
    }

    /**
     * 按省去统计
     */
    private ScreenVo statisticalProvince(Integer province) {
        return statistics(province, null, null, null);
    }

    /**
     * 统计全国
     */
    private ScreenVo nationalStatistics() {
        return statistics(null, null, null, null);
    }

    /**
     * 统计
     */
    private ScreenVo statistics(Integer province, Integer city, Integer district, Long parkInfoId) {
        // 判断是服务商还是系统管理员
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-获取停车大屏总数据，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        String screenTitle = "喜鹊云停车大数据可视化平台";
        Long deptId = null;
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            // 服务商统计名下所有的项目，用服务商ID去查询
            deptId = loginSystemUser.getSystemUser().getDeptId();
            log.info("[停车看板]-获取停车大屏总数据，根据服务商去统计，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);

            // 获取配置的大屏名称
            R<SystemDeptDTO> deptInfoResult = remoteSystemDeptService.getInfoById(deptId);
            if (deptInfoResult.getData() != null) {
                screenTitle = deptInfoResult.getData().getScreenTitle();
            }
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            // 项目管理员统计单个项目，用项目ID去查询
            parkInfoId = loginSystemUser.getParkId();
            log.info("[停车看板]-获取停车大屏总数据，根据项目管理员去统计，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);

            // 获取配置的大屏名称
            R<SystemProjectDTO> projectInfoResult = remoteSystemProjectService.getProjectInfo(parkInfoId);
            if (projectInfoResult.getData() != null) {
                screenTitle = projectInfoResult.getData().getScreenTitle();
            }
        } else {
            // 系统管理员统计全部
            log.info("[停车看板]-获取停车大屏总数据，系统管理员统计全部，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        }

        // 统计车辆进流水
        int carInStreamNum = carInStream(province, city, district, deptId, parkInfoId);

        // 统计车辆出流水
        int carOutStreamNum = carOutStream(province, city, district, deptId, parkInfoId);

        // 统计订单收入流水
        PayOrderDto parkOrderDto = orderStream(province, city, district, deptId, parkInfoId);
        int orderNum = 0;
        BigDecimal orderTotalMoney = BigDecimal.ZERO;
        if (parkOrderDto != null) {
            orderNum = parkOrderDto.getNum();
            orderTotalMoney = parkOrderDto.getTotalMoney().divide(new BigDecimal("100"), 2, RoundingMode.UP);
        }

        // 统计停车场总收入分析
        List<PayOrderDto> parkingTotalRevenueList = totalParkingRevenueAnalysis(province, city, district, deptId, parkInfoId);

        // 统计支付方式分析（近三日）
        PayOrderDto paymentMethodOnThreeDay = paymentMethodOnThreeDay(province, city, district, deptId, parkInfoId);

        // 统计停车场收入排行榜
        List<PayOrderDto> parkingRevenueRankingList = parkingRevenueRanking(province, city, district, deptId, parkInfoId);

        // 统计车辆实时状态
        List<ParkInDto> parkInLogList = carRealTimeStatus(province, city, district, deptId, parkInfoId);

        // 统计停车时常分析
        PayOrderDto parkingDuration = parkingDuration(province, city, district, deptId, parkInfoId);

        // 统计今天和昨天的车流量
        int endHour = DateUtils.getHour();
        int startHour = endHour - 9;
        List<ParkInDto> todayTrafficFlowList = trafficFlowByDayAndTime(DateUtils.getDate(), startHour, endHour, province, city, district, deptId, parkInfoId);
        List<ParkInDto> yesterdayTrafficFlowList = trafficFlowByDayAndTime(DateUtils.getYesterday(), startHour, endHour, province, city, district, deptId, parkInfoId);

        // 统计项目在线状态
        ParkInfoStatisticsDto parkInfoStatisticsDto = parkInfoService.selectOnLineStatus(province, city, district, deptId, parkInfoId);

        // 统计设备在线状态
        ParkDeviceStatisticsDto parkDeviceStatisticsDto = parkDeviceNewService.selectOnLineStatus(province, city, district, deptId, parkInfoId);

        // 统计通道在线状态
        ParkLaneStatisticsDto parkLaneStatisticsDto = parkLaneService.selectOnLineStatus(province, city, district, deptId, parkInfoId);

        // 统计年度总金额
        BigDecimal totalAnnualAmount = payOrderService.selectTotalAnnualAmount(province, city, district, deptId, parkInfoId);

        // 组装返回对象
        ScreenVo screenVo = new ScreenVo();
        // 组装车辆出入流水
        screenVo.setCarInStreamNum(carInStreamNum);
        screenVo.setCarOutStreamNum(carOutStreamNum);
        // 组装订单收入流水
        screenVo.setOrderNum(orderNum);
        screenVo.setOrderTotalMoney(orderTotalMoney);
        // 组装停车场总收入分析
        assembleParkTotalRevenueList(parkingTotalRevenueList, screenVo);
        // 组装支付方式分析
        assemblePaymentMethod(paymentMethodOnThreeDay, screenVo);
        // 组装停车场收入排行榜
        assembleParkRevenueRankingList(parkingRevenueRankingList, screenVo);
        // 组装车辆实时动态
        assembleCarRealtimeList(parkInLogList, screenVo);
        // 组装停车时长分析
        assembleParkingTime(parkingDuration, screenVo);
        // 组装车流量分析
        assembleTrafficFlowList(todayTrafficFlowList, yesterdayTrafficFlowList, screenVo);
        // 组装联线状态
        assembleOnline(parkInfoStatisticsDto, parkDeviceStatisticsDto, parkLaneStatisticsDto, screenVo);
        // 组装年度总金额
        screenVo.setTotalAnnualAmount(totalAnnualAmount.divide(new BigDecimal("100"), 2, RoundingMode.UP));

        screenVo.setScreenTitle(screenTitle);

        return screenVo;
    }

    /**
     * 组装联线状态
     */
    private void assembleOnline(ParkInfoStatisticsDto parkInfoStatisticsDto, ParkDeviceStatisticsDto parkDeviceStatisticsDto,
                                ParkLaneStatisticsDto parkLaneStatisticsDto, ScreenVo screenVo) {
        // 项目联线状态
        ParkOnlineVo projectOnline;
        if (parkInfoStatisticsDto != null) {
            projectOnline = ParkOnlineVo.builder()
                    .totalNum(parkInfoStatisticsDto.getTotalNum())
                    .onlineNum(parkInfoStatisticsDto.getOnlineNum())
                    .noOnlineNum(parkInfoStatisticsDto.getNoOnlineNum())
                    .onlineRate((int) (Double.valueOf(parkInfoStatisticsDto.getOnlineNum()) / Double.valueOf(parkInfoStatisticsDto.getTotalNum()) * 100D))
                    .build();
        } else {
            projectOnline = ParkOnlineVo.builder().totalNum(0).onlineNum(0).noOnlineNum(0).onlineRate(0).build();
        }
        screenVo.setProjectOnline(projectOnline);

        // 设备联线状态
        ParkOnlineVo equipmentOnline;
        if (parkDeviceStatisticsDto != null) {
            equipmentOnline = ParkOnlineVo.builder()
                    .totalNum(parkDeviceStatisticsDto.getTotalNum())
                    .onlineNum(parkDeviceStatisticsDto.getOnlineNum())
                    .noOnlineNum(parkDeviceStatisticsDto.getNoOnlineNum())
                    .onlineRate((int) (Double.valueOf(parkDeviceStatisticsDto.getOnlineNum()) / Double.valueOf(parkDeviceStatisticsDto.getTotalNum()) * 100D))
                    .build();
        } else {
            equipmentOnline = ParkOnlineVo.builder().totalNum(0).onlineNum(0).noOnlineNum(0).onlineRate(0).build();
        }
        screenVo.setEquipmentOnline(equipmentOnline);

        // 通道联线状态
        ParkOnlineVo channelOnline;
        if (parkLaneStatisticsDto != null) {
            channelOnline = ParkOnlineVo.builder()
                    .totalNum(parkLaneStatisticsDto.getTotalNum())
                    .onlineNum(parkLaneStatisticsDto.getOnlineNum())
                    .noOnlineNum(parkLaneStatisticsDto.getNoOnlineNum())
                    .onlineRate((int) (Double.valueOf(parkLaneStatisticsDto.getOnlineNum()) / Double.valueOf(parkLaneStatisticsDto.getTotalNum()) * 100D))
                    .build();
        } else {
            channelOnline = ParkOnlineVo.builder().totalNum(0).onlineNum(0).noOnlineNum(0).onlineRate(0).build();
        }
        screenVo.setChannelOnline(channelOnline);
    }

    /**
     * 组装车流量分析
     */
    private void assembleTrafficFlowList(List<ParkInDto> todayTrafficFlowList, List<ParkInDto> yesterdayTrafficFlowList,
                                         ScreenVo screenVo) {
        // 今日车流量分析
        if (CollectionUtils.isNotEmpty(todayTrafficFlowList)) {
            List<TrafficFlowVo> todayTrafficFlowVoList = new ArrayList<>();
            todayTrafficFlowList.forEach(parkInStatisticsDto -> {
                if (parkInStatisticsDto != null) {
                    TrafficFlowVo trafficFlowVo = TrafficFlowVo.builder()
                            .hourTime(parkInStatisticsDto.getHourTime())
                            .hourTrafficFlowNum(parkInStatisticsDto.getHourTrafficFlowNum())
                            .build();
                    todayTrafficFlowVoList.add(trafficFlowVo);
                }
            });
            screenVo.setTodayTrafficFlowList(todayTrafficFlowVoList);
        } else {
            screenVo.setTodayTrafficFlowList(Collections.emptyList());
        }

        // 昨日车流量分析
        if (CollectionUtils.isNotEmpty(yesterdayTrafficFlowList)) {
            List<TrafficFlowVo> yesterdayTrafficFlowVoList = new ArrayList<>();
            yesterdayTrafficFlowList.forEach(parkInStatisticsDto -> {
                if (parkInStatisticsDto != null) {
                    TrafficFlowVo trafficFlowVo = TrafficFlowVo.builder()
                            .hourTime(parkInStatisticsDto.getHourTime())
                            .hourTrafficFlowNum(parkInStatisticsDto.getHourTrafficFlowNum())
                            .build();
                    yesterdayTrafficFlowVoList.add(trafficFlowVo);
                }
            });
            screenVo.setYesterdayTrafficFlowList(yesterdayTrafficFlowVoList);
        } else {
            screenVo.setYesterdayTrafficFlowList(Collections.emptyList());
        }
    }

    /**
     * 组装停车时长分析
     */
    private void assembleParkingTime(PayOrderDto parkingDuration, ScreenVo screenVo) {
        // 停车时长分析
        ParkingTimeVo parkingTime;
        if (parkingDuration != null) {
            parkingTime = ParkingTimeVo.builder()
                    .oneLow(parkingDuration.getOneLow())
                    .ontToThree(parkingDuration.getOntToThree())
                    .fourToSeven(parkingDuration.getFourToSeven())
                    .eightToEleven(parkingDuration.getEightToEleven())
                    .twelveToFifteen(parkingDuration.getTwelveToFifteen())
                    .sixteenToTwentyFour(parkingDuration.getSixteenToTwentyFour())
                    .twentyFourUp(parkingDuration.getTwentyFourUp())
                    .build();
        } else {
            parkingTime = ParkingTimeVo.builder().oneLow(0).ontToThree(0).fourToSeven(0).eightToEleven(0).twelveToFifteen(0)
                    .sixteenToTwentyFour(0).twentyFourUp(0).build();
        }
        screenVo.setParkingTime(parkingTime);
    }

    /**
     * 组装车辆实时动态
     */
    private void assembleCarRealtimeList(List<ParkInDto> parkInLogList, ScreenVo screenVo) {
        // 车辆实时动态
        if (CollectionUtils.isNotEmpty(parkInLogList)) {
            List<CarRealtimeVo> carRealtimeVoList = new ArrayList<>();
            parkInLogList.forEach(parkInStatisticsDto -> {
                if (parkInStatisticsDto != null) {
                    CarRealtimeVo carRealtimeVo = CarRealtimeVo.builder()
                            .inCarPlate(parkInStatisticsDto.getInCarPlate())
                            .inTime(parkInStatisticsDto.getInTime())
                            .parkName(parkInStatisticsDto.getParkName())
                            .build();
                    carRealtimeVoList.add(carRealtimeVo);
                }
            });
            screenVo.setCarRealtimeList(carRealtimeVoList);
        } else {
            screenVo.setCarRealtimeList(Collections.emptyList());
        }
    }

    /**
     * 组装停车场收入排行榜
     */
    private void assembleParkRevenueRankingList(List<PayOrderDto> parkingRevenueRankingList, ScreenVo screenVo) {
        // 停车场收入排行榜
        if (CollectionUtils.isNotEmpty(parkingRevenueRankingList)) {
            List<ParkRevenueRankingVo> parkRevenueRankingVoList = new ArrayList<>();
            parkingRevenueRankingList.forEach(payOrderStatisticsDto -> {
                if (payOrderStatisticsDto != null) {
                    ParkRevenueRankingVo parkRevenueRankingVo = ParkRevenueRankingVo.builder()
                            .parkName(payOrderStatisticsDto.getParkName())
                            .totalMoney(payOrderStatisticsDto.getTotalMoney().divide(new BigDecimal("100"), 2, RoundingMode.UP))
                            .build();
                    parkRevenueRankingVoList.add(parkRevenueRankingVo);
                }
            });
            screenVo.setParkRevenueRankingList(parkRevenueRankingVoList);
        } else {
            screenVo.setParkRevenueRankingList(Collections.emptyList());
        }
    }

    /**
     * 组装停车场总收入分析
     */
    private void assembleParkTotalRevenueList(List<PayOrderDto> parkingTotalRevenueList, ScreenVo screenVo) {
        if (CollectionUtils.isNotEmpty(parkingTotalRevenueList)) {
            List<ParkTotalRevenueVo> parkTotalRevenueVoList = new ArrayList<>();
            parkingTotalRevenueList.forEach(payOrderStatisticsDto -> {
                if (payOrderStatisticsDto != null) {
                    ParkTotalRevenueVo parkTotalRevenueAnalysisVo = ParkTotalRevenueVo.builder()
                            .month(payOrderStatisticsDto.getMonth())
                            .totalMoney(payOrderStatisticsDto.getTotalMoney().divide(new BigDecimal("100"), 2, RoundingMode.UP))
                            .build();
                    parkTotalRevenueVoList.add(parkTotalRevenueAnalysisVo);
                }
            });
            screenVo.setParkTotalRevenueList(parkTotalRevenueVoList);
        } else {
            screenVo.setParkTotalRevenueList(Collections.emptyList());
        }
    }

    /**
     * 组装支付方式分析
     */
    private void assemblePaymentMethod(PayOrderDto paymentMethodOnThreeDay, ScreenVo screenVo) {
        PaymentMethodVo paymentMethodVoToThreeDay;
        BigDecimal hundred = new BigDecimal("100");
        if (paymentMethodOnThreeDay != null) {
            paymentMethodVoToThreeDay = PaymentMethodVo.builder()
                    .monthlyCardPrice(paymentMethodOnThreeDay.getMonthlyCardPrice().divide(hundred, 2, RoundingMode.UP))
                    .rechargePrice(paymentMethodOnThreeDay.getRechargePrice().divide(hundred, 2, RoundingMode.UP))
                    .temporaryStopPrice(paymentMethodOnThreeDay.getTemporaryStopPrice().divide(hundred, 2, RoundingMode.UP))
                    .build();
        } else {
            paymentMethodVoToThreeDay = PaymentMethodVo.builder()
                    .monthlyCardPrice(BigDecimal.ZERO)
                    .rechargePrice(BigDecimal.ZERO)
                    .temporaryStopPrice(BigDecimal.ZERO)
                    .build();
        }
        screenVo.setPaymentMethodToThreeDay(paymentMethodVoToThreeDay);
    }

    /**
     * 统计某时间段的车流量
     */
    private List<ParkInDto> trafficFlowByDayAndTime(String day, Integer startHour, Integer endHour,
                                                    Integer province, Integer city, Integer district,
                                                    Long deptId, Long parkInfoId) {
        return parkInService.selectTrafficFlowByDateAndTime(day, startHour, endHour, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计停车时常分析
     */
    private PayOrderDto parkingDuration(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        String startTime = DateUtils.getPastDate(3);
        String endTime = DateUtils.getDate();
        return payOrderService.selectParkingDuration(startTime, endTime, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计车辆实时状态
     */
    private List<ParkInDto> carRealTimeStatus(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        int limit = 10;
        return parkInService.selectParkInRealTimeStatus(limit, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计停车场收入排行榜
     */
    private List<PayOrderDto> parkingRevenueRanking(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        int limit = 6;
        return payOrderService.selectParkingRevenueRanking(limit, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计支付方式分析（近三日）
     */
    private PayOrderDto paymentMethodOnThreeDay(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        int threePastDay = 3;
        String startTime = DateUtils.getPastDate(threePastDay);
        String endTime = DateUtils.getDate();
        return payOrderService.selectPaymentMethodOnThreeDay(startTime, endTime, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计停车场总收入分析
     */
    private List<PayOrderDto> totalParkingRevenueAnalysis(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        // 获取当前年月
        int year = DateUtils.getYears();
        int month = DateUtils.getMonth();
        int intervalMonth = 5;
        int startMonth = month - intervalMonth;
        return payOrderService.selectParkingOrderCountByMonth(year, startMonth, month, province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计订单收入流水
     */
    private PayOrderDto orderStream(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        return payOrderService.selectParkingOrderByToday(province, city, district, deptId, parkInfoId);
    }

    /**
     * 计算车辆进流水
     */
    private Integer carInStream(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        return parkInService.selectParkInfoNumByToday(province, city, district, deptId, parkInfoId);
    }

    /**
     * 计算车辆出流水
     */
    private Integer carOutStream(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        return parkOutService.selectParkInfoNumByToday(province, city, district, deptId, parkInfoId);
    }

    @Override
    public ScreenVo areaBaseInfo(Integer country, Integer province, Integer city, Integer district, Long parkInfoId) {
        if (parkInfoId != null) {
            // 按项目去统计
            return areaBaseInfoByParkInfo(province, city, district, parkInfoId);
        } else if (district != null) {
            // 按区县去统计
            return areaBaseInfoByDistrict(province, city, district);
        } else if (city != null) {
            // 按市去统计
            return areaBaseInfoByCity(province, city);
        } else if (province != null) {
            // 按省去统计
            return areaBaseInfoByProvince(province);
        } else if (country != null) {
            // 统计全国
            return areaBaseInfoByCountry();
        } else {
            // 统计全国
            return areaBaseInfoByCountry();
        }
    }

    private ScreenVo areaBaseInfoByParkInfo(Integer province, Integer city, Integer district, Long parkInfoId) {
        return statisticsAreaBaseInfo(province, city, district, parkInfoId);
    }

    private ScreenVo areaBaseInfoByDistrict(Integer province, Integer city, Integer district) {
        return statisticsAreaBaseInfo(province, city, district, null);
    }

    private ScreenVo areaBaseInfoByCity(Integer province, Integer city) {
        return statisticsAreaBaseInfo(province, city, null, null);
    }

    private ScreenVo areaBaseInfoByProvince(Integer province) {
        return statisticsAreaBaseInfo(province, null, null, null);
    }

    private ScreenVo areaBaseInfoByCountry() {
        return statisticsAreaBaseInfo(null, null, null, null);
    }

    private ScreenVo statisticsAreaBaseInfo(Integer province, Integer city, Integer district, Long parkInfoId) {
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-获取区域内的停车场数量、今日收入以及支付方式，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        Long deptId = null;
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            // 服务商统计名下所有的项目，用服务商ID去查询
            deptId = loginSystemUser.getSystemUser().getDeptId();
            log.info("[停车看板]-获取区域内的停车场数量、今日收入以及支付方式，根据服务商去统计，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            // 项目管理员统计单个项目，用项目ID去查询
            parkInfoId = loginSystemUser.getParkId();
            log.info("[停车看板]-获取区域内的停车场数量、今日收入以及支付方式，根据项目管理员去统计，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        } else {
            // 系统管理员统计全部
            log.info("[停车看板]-获取区域内的停车场数量、今日收入以及支付方式，系统管理员统计全部，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        }

        int parkNum = selectParkNum(province, city, district, deptId, parkInfoId);
        BigDecimal incomeToday = selectIncomeToday(province, city, district, deptId, parkInfoId);
        PayOrderDto payOrderStatisticsDto = paymentMethodToday(province, city, district, deptId, parkInfoId);

        ScreenVo screenVo = new ScreenVo();
        BigDecimal hundred = new BigDecimal("100");
        screenVo.setParkNum(parkNum);
        screenVo.setIncomeToday(incomeToday.divide(hundred, 2, RoundingMode.UP));
        // 电子支付 = 微信支付 + 支付宝支付
        screenVo.setElectronicPayNum((payOrderStatisticsDto.getWxPayPrice().add(payOrderStatisticsDto.getAliPayPrice()))
                .divide(hundred, 2, RoundingMode.UP));
        // 现金支付
        screenVo.setCashPayNum(payOrderStatisticsDto.getCashPrice().divide(hundred, 2, RoundingMode.UP));
        // 其他支付 = P云 + ETC + 余额 + 免费
        screenVo.setOtherPayNum((payOrderStatisticsDto.getPCloudPrice()
                .add(payOrderStatisticsDto.getEtcPrice())
                .add(payOrderStatisticsDto.getBalancePrice())
                .add(payOrderStatisticsDto.getFreePrice())).divide(hundred, 2, RoundingMode.UP));
        return screenVo;
    }

    /**
     * 统计区域内的停车场数量
     */
    private Integer selectParkNum(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        return parkInfoService.selectParkNum(province, city, district, deptId, parkInfoId);
    }

    /**
     * 统计区域内的今日收入
     */
    private BigDecimal selectIncomeToday(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        PayOrderDto payOrderStatisticsDto = payOrderService.selectParkingOrderByToday(province, city, district, deptId, parkInfoId);
        if (payOrderStatisticsDto != null) {
            return payOrderStatisticsDto.getTotalMoney();
        } else {
            return BigDecimal.ZERO;
        }
    }

    /**
     * 统计区域内的今日支付方式
     */
    private PayOrderDto paymentMethodToday(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        return payOrderService.selectPaymentMethodToday(province, city, district, deptId, parkInfoId);
    }

    @Override
    public List<ParkBaseInfoVo> selectParkList(Integer country, Integer province, Integer city, Integer district) {
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-查询省市区内的项目列表，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        Long deptId = null;
        Long parkInfoId = null;
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            deptId = loginSystemUser.getSystemUser().getDeptId();
            log.info("[停车看板]-查询省市区内的项目列表，根据服务商去查询，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            parkInfoId = loginSystemUser.getParkId();
            log.info("[停车看板]-查询省市区内的项目列表，根据项目管理员去查询，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        } else {
            log.info("[停车看板]-查询省市区内的项目列表，系统管理员查询全部，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}", province, city, district, deptId, parkInfoId);
        }
        List<ParkInfoStatisticsDto> parkInfoDtoList = parkInfoService.selectParkListByArea(country, province, city, district, deptId, parkInfoId);
        if (CollectionUtils.isNotEmpty(parkInfoDtoList)) {
            List<ParkBaseInfoVo> parkBaseInfoVoList = new ArrayList<>();
            parkInfoDtoList.forEach(parkInfoStatisticsDto -> {
                if (parkInfoStatisticsDto != null) {
                    ParkBaseInfoVo parkBaseInfoVo = ParkBaseInfoVo.builder()
                            .parkId(parkInfoStatisticsDto.getId())
                            .parkName(parkInfoStatisticsDto.getName())
                            .build();
                    parkBaseInfoVoList.add(parkBaseInfoVo);
                }
            });
            return parkBaseInfoVoList;
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    public List<Integer> selectParkExist(Integer country, Integer province, Integer city, Integer district) {
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-查询指定区域内是否有项目存在，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        Long deptId = null;
        Long parkInfoId = null;
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            deptId = loginSystemUser.getSystemUser().getDeptId();
            log.info("[停车看板]-查询指定区域内是否有项目存在，根据服务商去查询，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}",
                    province, city, district, deptId, parkInfoId);
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            parkInfoId = loginSystemUser.getParkId();
            log.info("[停车看板]-查询指定区域内是否有项目存在，根据项目管理员去查询，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}",
                    province, city, district, deptId, parkInfoId);
        } else {
            log.info("[停车看板]-查询指定区域内是否有项目存在，系统管理员查询全部，省份：{}，市：{}，区县：{}，服务商ID：{}，项目ID：{}",
                    province, city, district, deptId, parkInfoId);
        }

        if (district != null) {
            // 统计指定区县下的项目列表
            return selectParkExistByOneDistrict(province, city, district, deptId, parkInfoId);
        } else if (city != null) {
            // 统计指定市下每个区县的项目列表
            return selectParkExistByDistrict(province, city, deptId, parkInfoId);
        } else if (province != null) {
            // 统计指定省份下每个市的项目列表
            return selectParkExistByCity(province, deptId, parkInfoId);
        } else if (country != null) {
            // 统计每个省的项目列表
            return selectParkExistByProvince(deptId, parkInfoId);
        } else {
            // 统计每个省的项目列表
            return selectParkExistByProvince(deptId, parkInfoId);
        }
    }

    /**
     * 统计指定区县下的项目列表
     */
    private List<Integer> selectParkExistByOneDistrict(Integer province, Integer city, Integer district, Long deptId, Long parkInfoId) {
        // 查询指定区县的项目列表
        List<ParkInfoStatisticsDto> parkInfoStatisticsDtoList = parkInfoService.selectParkListByArea(null, province, city, district,
                deptId, parkInfoId);
        if (CollectionUtils.isNotEmpty(parkInfoStatisticsDtoList)) {
            return Collections.singletonList(district);
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * 统计指定市下每个区县的项目列表
     */
    private List<Integer> selectParkExistByDistrict(Integer province, Integer city, Long deptId, Long parkInfoId) {
        // 查询指定市下的区县编码列表
        List<Area> districtCodeList = areaService.selectDistrictByCity(city);

        List<Integer> parkExistVoList = new ArrayList<>();

        // 查询每个区县的项目列表
        districtCodeList.forEach(area -> {
            // 获取区县编码
            Integer districtCode = Integer.parseInt(area.getAreaCode());
            // 查询指定区县的项目列表
            List<ParkInfoStatisticsDto> parkInfoStatisticsDtoList = parkInfoService.selectParkListByArea(null, province, city, districtCode,
                    deptId, parkInfoId);
            if (CollectionUtils.isNotEmpty(parkInfoStatisticsDtoList)) {
                parkExistVoList.add(districtCode);
            }
        });
        return parkExistVoList;
    }

    /**
     * 统计指定省份下每个市的项目列表
     */
    private List<Integer> selectParkExistByCity(Integer province, Long deptId, Long parkInfoId) {
        // 查询指定省份下的市区编码列表
        List<Area> cityCodeList = areaService.selectCityByProvince(province);

        List<Integer> parkExistVoList = new ArrayList<>();

        // 查询每个市的项目列表
        cityCodeList.forEach(area -> {
            // 获取城市编码
            Integer cityCode = Integer.parseInt(area.getAreaCode());

            // 查询指定城市的项目列表
            List<ParkInfoStatisticsDto> parkInfoStatisticsDtoList = parkInfoService.selectParkListByArea(null, province, cityCode, null,
                    deptId, parkInfoId);
            if (CollectionUtils.isNotEmpty(parkInfoStatisticsDtoList)) {
                parkExistVoList.add(cityCode);
            }
        });
        return parkExistVoList;
    }

    /**
     * 统计每个省的项目列表
     */
    private List<Integer> selectParkExistByProvince(Long deptId, Long parkInfoId) {
        // 查询所有省的编码列表
        List<Area> provinceCodeList = areaService.selectAllProvinceCode();

        List<Integer> parkExistVoList = new ArrayList<>();

        provinceCodeList.forEach(area -> {
            // 获取省编码
            Integer provinceCode = Integer.parseInt(area.getAreaCode());
            // 查询指定省份的项目列表
            List<ParkInfoStatisticsDto> parkInfoStatisticsDtoList = parkInfoService.selectParkListByArea(null, provinceCode, null, null
                    , deptId, parkInfoId);
            if (CollectionUtils.isNotEmpty(parkInfoStatisticsDtoList)) {
                parkExistVoList.add(provinceCode);
            }
        });
        return parkExistVoList;
    }

    @Override
    public ScreenVo selectDisplayLevel() {
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-获取地图显示的级别，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        String chinaCode = "100000";
        String chinaName = "中国";
        ScreenVo screenVo = new ScreenVo();
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            long deptId = loginSystemUser.getSystemUser().getDeptId();
            log.info("[停车看板]-获取地图显示的级别，根据服务商去查询，服务商ID：{}", deptId);
            // 如果是服务商，则获取该服务商的所有项目
            List<ParkInfo> parkInfoList = parkInfoService.selectParkInfoByDeptId(deptId);
            if (CollectionUtils.isEmpty(parkInfoList)) {
                screenVo.setParent(chinaCode);
                screenVo.setName(chinaName);
                screenVo.setLevel(AreaLevel.COUNTRY.getLevel());
                return screenVo;
            }
            // 判断项目个数，如果只有一个项目，则返回项目信息
            if (parkInfoList.size() == 1) {
                ParkInfo parkInfo = parkInfoList.get(0);
                long parkInfoId = parkInfo.getId();
                screenVo.setParent(String.valueOf(parkInfoId));
                screenVo.setName(parkInfo.getName());
                screenVo.setLevel(AreaLevel.PROJECT.getLevel());
            } else {
                Set<String> provinceSet = new HashSet<>();
                Set<String> citySet = new HashSet<>();
                Set<String> districtSet = new HashSet<>();
                parkInfoList.forEach(parkInfo -> {
                    provinceSet.add(parkInfo.getProvince());
                    citySet.add(parkInfo.getCity());
                    districtSet.add(parkInfo.getDistrict());
                });

                String areaCode;
                // 是否是同一个省
                if (provinceSet.size() == 1) {
                    // 是否是同一个市
                    if (citySet.size() == 1) {
                        // 同一个市，则返回市的编码
                        areaCode = citySet.stream().iterator().next();
                        screenVo.setParent(areaCode);
                        screenVo.setName(areaService.getOneByAreaCode(areaCode).getAreaName());
                        screenVo.setLevel(AreaLevel.CITY.getLevel());
                        if (districtSet.size() == 1) {
                            // 同一个区县，返回区县编码
                            areaCode = districtSet.stream().iterator().next();
                            screenVo.setParent(areaCode);
                            screenVo.setName(areaService.getOneByAreaCode(areaCode).getAreaName());
                            screenVo.setLevel(AreaLevel.DISTRICT.getLevel());
                        } else {
                            // 不是同一个区县，返回市的编码
                            areaCode = citySet.stream().iterator().next();
                            screenVo.setParent(areaCode);
                            screenVo.setName(areaService.getOneByAreaCode(areaCode).getAreaName());
                            screenVo.setLevel(AreaLevel.CITY.getLevel());
                        }
                    } else {
                        // 不是同一个市，则返回省的编码
                        areaCode = provinceSet.stream().iterator().next();
                        screenVo.setParent(areaCode);
                        screenVo.setName(areaService.getOneByAreaCode(areaCode).getAreaName());
                        screenVo.setLevel(AreaLevel.PROVINCE.getLevel());
                    }
                } else {
                    // 不是同一个省，返回国家编码
                    screenVo.setParent(chinaCode);
                    screenVo.setName(chinaName);
                    screenVo.setLevel(AreaLevel.COUNTRY.getLevel());
                }
            }
            return screenVo;
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            // 如果是项目管理员，则返回该项目信息
            long parkInfoId = loginSystemUser.getParkId();
            log.info("[停车看板]-获取地图显示的级别，根据项目管理员去查询，项目ID：{}", parkInfoId);
            // 根据项目ID获取项目信息
            ParkInfo parkInfo = parkInfoService.selectParkInfoById(parkInfoId);
            if (parkInfo != null) {
                screenVo.setParent(String.valueOf(parkInfoId));
                screenVo.setName(parkInfo.getName());
                screenVo.setLevel(AreaLevel.PROJECT.getLevel());
            }
            return screenVo;
        } else {
            log.info("[停车看板]-获取地图显示的级别，系统管理员查询全部");
            // 如果是系统管理员，返回国家编码
            screenVo.setParent(chinaCode);
            screenVo.setName(chinaName);
            screenVo.setLevel(AreaLevel.COUNTRY.getLevel());
            return screenVo;
        }
    }

    @Override
    public ScreenTreeVo selectTree() {
        LoginSystemUser loginSystemUser = tokenService.getLoginUser();
        if (loginSystemUser == null) {
            log.warn("[停车看板]-获取项目树形结构，登录用户获取失败");
            throw new IllegalArgumentException(LOGIN_USER_GET_ERROR);
        }
        List<ScreenTreeVo> list;
        ScreenTreeVo screenTreeVo = ScreenTreeVo.builder().parent(100000).name("中国").level(AreaLevel.COUNTRY.getLevel()).build();
        if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.SERVICE_MANAGER)) {
            long deptId = loginSystemUser.getSystemUser().getDeptId();
            log.warn("[停车看板]-获取项目树形结构，根据服务商查询，服务商ID：{}", deptId);
            List<ParkInfo> parkInfoList = parkInfoService.selectParkInfoByDeptId(deptId);
            list = new ArrayList<>(handleTree(parkInfoList).values());
        } else if (Objects.equals(loginSystemUser.getUserType(), UserConstants.UserType.PROJECT_MANAGER)) {
            long parkInfoId = loginSystemUser.getParkId();
            log.warn("[停车看板]-获取项目树形结构，根据项目管理员查询，项目ID：{}", parkInfoId);
            ParkInfo parkInfo = parkInfoService.selectParkInfoById(parkInfoId);
            list = new ArrayList<>(handleTree(Collections.singletonList(parkInfo)).values());
        } else {
            log.warn("[停车看板]-获取项目树形结构，根据系统管理员查询");
            List<ParkInfo> parkInfoList = parkInfoService.selectAll();
            list = new ArrayList<>(handleTree(parkInfoList).values());
        }
        screenTreeVo.setChildren(list);
        return sign(screenTreeVo);
    }

    /**
     * 标记
     */
    private ScreenTreeVo sign(ScreenTreeVo screenTreeVo) {
        if (screenTreeVo != null) {
            List<ScreenTreeVo> provinceList = screenTreeVo.getChildren();
            if (CollectionUtils.isNotEmpty(provinceList)) {
                if (provinceList.size() == 1) {
                    // 只存在一个省，则继续往下判断
                    ScreenTreeVo province = provinceList.get(0);
                    List<ScreenTreeVo> cityList = province.getChildren();
                    if (cityList.size() == 1) {
                        // 只存在一个市，则继续往下判断
                        ScreenTreeVo city = cityList.get(0);
                        List<ScreenTreeVo> districtList = city.getChildren();
                        if (districtList.size() == 1) {
                            // 只存在一个区县，则从项目开始标记
                            ScreenTreeVo district = districtList.get(0);
                            List<ScreenTreeVo> projectList = district.getChildren();
                            projectList.forEach(project -> project.setSign(true));
                        } else {
                            // 存在多个区县，则从市开始往下标记
                            city.setSign(true);
                            districtList.forEach(district -> {
                                district.setSign(true);
                                List<ScreenTreeVo> projectList = district.getChildren();
                                projectList.forEach(project -> project.setSign(true));
                            });
                        }
                    } else {
                        // 存在多个市，则从省开始往下标记
                        province.setSign(true);
                        cityList.forEach(city -> {
                            city.setSign(true);
                            List<ScreenTreeVo> districtList = city.getChildren();
                            districtList.forEach(district -> {
                                district.setSign(true);
                                List<ScreenTreeVo> projectList = district.getChildren();
                                projectList.forEach(project -> project.setSign(true));
                            });
                        });
                    }
                } else {
                    // 存在多个省，则从国开始往下标记
                    screenTreeVo.setSign(true);
                    provinceList.forEach(province -> {
                        province.setSign(true);
                        List<ScreenTreeVo> cityList = province.getChildren();
                        cityList.forEach(city -> {
                            city.setSign(true);
                            List<ScreenTreeVo> districtList = city.getChildren();
                            districtList.forEach(district -> {
                                district.setSign(true);
                                List<ScreenTreeVo> projectList = district.getChildren();
                                projectList.forEach(project -> project.setSign(true));
                            });
                        });
                    });
                }
            } else {
                // 不存在项目，则在全国打标记
                screenTreeVo.setSign(true);
            }
        }
        return screenTreeVo;
    }

    private Map<String, ScreenTreeVo> handleTree(List<ParkInfo> parkInfoList) {
        Map<String, ScreenTreeVo> result = new HashMap<>(16);
        if (CollectionUtils.isNotEmpty(parkInfoList)) {
            // 处理
            parkInfoList.forEach(parkInfo -> {

                String nowProvinceCode = parkInfo.getProvince();
                String nowCityCode = parkInfo.getCity();
                String nowDistrictCode = parkInfo.getDistrict();

                ScreenTreeVo provinceVo = result.get(nowProvinceCode);

                // 判断省是否存在
                if (provinceVo == null) {
                    // ----------------- 省不存在，增加省的信息，包含市信息、区县信息、项目信息

                    // 项目信息
                    ScreenTreeVo newProjectVo = handleScreenTreeVo(String.valueOf(parkInfo.getId()), parkInfo.getName(),
                            AreaLevel.PROJECT.getLevel(), null);
                    // 区县信息
                    ScreenTreeVo newDistrictVo = handleScreenTreeVo(parkInfo.getDistrict(), null, AreaLevel.DISTRICT.getLevel(), newProjectVo);
                    // 市信息
                    ScreenTreeVo newCityVo = handleScreenTreeVo(parkInfo.getCity(), null, AreaLevel.CITY.getLevel(), newDistrictVo);
                    // 增加省
                    provinceVo = handleScreenTreeVo(nowProvinceCode, null, AreaLevel.PROVINCE.getLevel(), newCityVo);

                    result.put(nowProvinceCode, provinceVo);
                } else {
                    // ----------------- 省已经存在，获取省已经存下来得市列表
                    List<ScreenTreeVo> cityList = provinceVo.getChildren();
                    // 判断市是否存在
                    boolean cityExist = false;
                    for (ScreenTreeVo cityVo : cityList) {
                        Integer cityCode = cityVo.getParent();
                        if (Objects.equals(String.valueOf(cityCode), nowCityCode)) {
                            cityExist = true;
                            // ----------------- 市已经存在，获取市已经存下来得区县列表
                            List<ScreenTreeVo> districtList = cityVo.getChildren();
                            // 判断区县是否存在
                            boolean districtExist = false;
                            for (ScreenTreeVo districtVo : districtList) {
                                Integer districtCode = districtVo.getParent();
                                if (Objects.equals(String.valueOf(districtCode), nowDistrictCode)) {
                                    districtExist = true;
                                    // 增加区县包含的项目信息
                                    ScreenTreeVo newProjectVo = handleScreenTreeVo(String.valueOf(parkInfo.getId()), parkInfo.getName(),
                                            AreaLevel.PROJECT.getLevel(), null);

                                    districtVo.getChildren().add(newProjectVo);
                                }
                            }

                            // ----------------- 区县不存在，增加区县的信息，包含项目信息
                            if (!districtExist) {
                                // 项目信息
                                ScreenTreeVo newProjectVo = handleScreenTreeVo(String.valueOf(parkInfo.getId()), parkInfo.getName(),
                                        AreaLevel.PROJECT.getLevel(), null);

                                // 区县信息
                                ScreenTreeVo newDistrictVo = handleScreenTreeVo(parkInfo.getDistrict(), null,
                                        AreaLevel.DISTRICT.getLevel(), newProjectVo);

                                cityVo.getChildren().add(newDistrictVo);
                            }

                        }
                    }

                    // ----------------- 市不存在，增加市的信息，包含项目信息和区县信息
                    if (!cityExist) {
                        // 项目信息
                        ScreenTreeVo newProjectVo = handleScreenTreeVo(String.valueOf(parkInfo.getId()), parkInfo.getName(),
                                AreaLevel.PROJECT.getLevel(), null);

                        // 区县信息
                        ScreenTreeVo newDistrictVo = handleScreenTreeVo(parkInfo.getDistrict(), null, AreaLevel.DISTRICT.getLevel(), newProjectVo);

                        // 市信息
                        ScreenTreeVo newCityVo = handleScreenTreeVo(parkInfo.getCity(), null, AreaLevel.CITY.getLevel(), newDistrictVo);

                        provinceVo.getChildren().add(newCityVo);
                    }
                }
            });
        }
        return result;
    }

    public ScreenTreeVo handleScreenTreeVo(String parent, String name, String level, ScreenTreeVo childrenVo) {
        ScreenTreeVo screenTreeVo = new ScreenTreeVo();
        screenTreeVo.setParent(Integer.parseInt(parent));
        screenTreeVo.setLevel(level);
        if (StringUtils.isNotEmpty(name)) {
            screenTreeVo.setName(name);
        } else {
            Area area = areaService.getOneByAreaCode(parent);
            if (area != null) {
                screenTreeVo.setName(area.getAreaName());
            }
        }
        if (childrenVo != null) {
            screenTreeVo.setChildren(new ArrayList<>(Collections.singletonList(childrenVo)));
        }
        return screenTreeVo;
    }

}
